package com.wzapp.sitposture.config.redis.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis的字符串处理工具，另外一种用法
 *
 * @author ql
 *
 */
@Service
public class RedisService {

    private static final Logger log = LoggerFactory.getLogger(RedisService.class);

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 写入缓存
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return result;
    }

    /**
     * 写入缓存设置时效时间
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return result;
    }

    /**
     * 原子性的递增
     *
     * @param key
     * @param increment
     * @param expireTime
     * @return
     */
    public Long increment(final String key, Long increment, Long expireTime) {
        Long count = 0L;
        try {
            count = redisTemplate.opsForValue().increment(key, 1);
            if (count > 1) {
                // 设置有效期
                redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }

        return count;
    }

    /**
     * 批量删除对应的value
     *
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key
     *
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0){
            redisTemplate.delete(keys);
        }
    }

    /**
     * 删除对应的value
     *
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断缓存中是否有对应的value
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 读取缓存
     *
     * @param key
     * @return
     */
    public Object get(final String key) {
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        return operations.get(key);
    }

    /**
     * 查询key的超时时间
     *
     * @param key
     * @return
     */
    public Long expireTime(final String key) {
        Long expireTime = redisTemplate.boundValueOps(key).getExpire();
        return expireTime;
    }

    /**
     * 哈希 添加
     *
     * @param key
     * @param hashKey
     * @param value
     */
    public void hmSet(String key, Object hashKey, Object value) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put(key, hashKey, value);
    }

    /**
     * 哈希获取数据
     *
     * @param key
     * @param hashKey
     * @return
     */
    public Object hmGet(String key, Object hashKey) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        return hash.get(key, hashKey);
    }

    /**
     * 哈希删除Hkey
     *
     * @param key
     * @param hashKey
     * @return
     */
    public void hmDelete(String key, Object hashKey) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.delete(key, hashKey);
    }

    /**
     * 功能: 哈希获取某个key的所有Hkey <br/>
     *
     * @param key
     * @return
     * @author ql
     * @date 2018-05-25 19:29
     */
    public Map<String, Object> hmGetAll(String key) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        Set<Object> hkeys = hash.keys(key);
        Map<String, Object> result = new HashMap<>();
        if (null != hkeys && hkeys.size() > 0) {
            for (Object hkey : hkeys) {
                result.put(hkey + "",  hash.get(key, hkey));
            }
        }
        return result;
    }

    /**
     * 功能: 哈希数据增加 <br/>
     *
     * @param key
     * @param hashKey
     * @param value
     * @return
     * @author ql
     * @date 2018-05-25 15:20
     */
    public void hmIncrese(String key, Object hashKey, Long value) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        Object oldValue = hash.get(key, hashKey);
        Long newValue = value + (Long) oldValue;
        hash.put(key, hashKey, newValue);
        return;
    }

    /**
     * 功能: 哈希数据增加或者值计算和 <br/>
     *
     * @param key
     * @param hashKey
     * @param value
     * @return
     * @author ql
     * @date 2018-05-25 15:50
     */
    public void hmSetOrIncrese(String key, Object hashKey, Long value) {
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        if (hash.hasKey(key, hashKey)) {
            Object oldValue = hash.get(key, hashKey);
            Long newValue = value + (Long) oldValue;
            hash.put(key, hashKey, newValue);
        } else {
            hash.put(key, hashKey, value);
        }
    }

    /**
     * 列表添加
     *
     * @param k
     * @param v
     */
    public void lPush(String k, Object v) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k, v);
    }

    /**
     * 列表获取
     *
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1) {
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k, l, l1);
    }

    /**
     * 集合添加
     *
     * @param key
     * @param value
     */
    public void add(String key, Object value) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key, value);
    }

    /**
     * 集合删除某个值
     *
     * @param key
     * @param value
     */
    public void delete(String key, Object value) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.remove(key, value);
    }

    /**
     * 集合获取
     *
     * @param key
     * @return
     */
    public Set<Object> getMembers(String key) {
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 有序集合添加
     *
     * @param key
     * @param value
     * @param scoure
     */
    public void zAdd(String key, Object value, double scoure) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key, value, scoure);
    }

    /**
     * 有序集合获取
     *
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */
    public Set<Object> rangeByScore(String key, double scoure, double scoure1) {
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.rangeByScore(key, scoure, scoure1);
    }

    /**
     * 批量设置redis
     *
     * @param key
     * @param keySet
     * @param statistics
     */
    public void pipelineHmSet(String key,String keySet, Map<String, Long> statistics){

        redisTemplate.executePipelined(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> redisOperations) throws DataAccessException {
                HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
                SetOperations<String, Object> set = redisTemplate.opsForSet();
                for (String hashKey : statistics.keySet()) {
                    hash.put(key, hashKey, statistics.get(hashKey));
                    set.add(keySet, key);
                }
                return null;
            }
        });
    }
}
